import { SetupContext, computed, defineComponent, ref } from "vue";
import { TransferProps, transferProps } from "./transfer.props";
import FListView from '../../list-view/src/list-view.component';
import './transfer.css';

export default defineComponent({
    name: 'FTransfer',
    props: transferProps,
    emits: ['change'],
    setup(props: TransferProps, context: SetupContext) {
        const identifyField = ref(props.identifyField);
        const selectionTitle = ref('已选：');
        const selectionItemTitle = ref('项数据');
        const displayType = ref(props.displayType);
        const fillToParent = ref(false);

        const dataSource = ref(props.dataSource);
        const selections = ref<any[]>(props.selections || []);
        const selectionValues = computed(() => selections.value.map((seletedItem: any) => seletedItem[identifyField.value]));
        const selectionMaps = new Map<string, any>();

        function initializeData() {
            const selectionValueMaps = new Map<string, boolean>();
            const originalSelectionValues = props.selectionValues || [];
            if (originalSelectionValues.length) {
                originalSelectionValues.reduce((result: Map<string, boolean>, selectionValue: string) => {
                    result.set(selectionValue, true);
                    return result;
                }, selectionValueMaps);
            }
            const originalSelections = props.selections || [];
            if (originalSelections.length) {
                selectionValueMaps.clear();
                originalSelections.reduce((result: Map<string, boolean>, selectedItem: any) => {
                    result.set(selectedItem[identifyField.value], true);
                    return result;
                }, selectionValueMaps);
            }
            if (!selections.value.length) {
                selections.value = dataSource.value
                    .filter((dataItem: any) => selectionValueMaps.has(dataItem[identifyField.value]))
                    .map((selectedItem: any) => Object.assign({}, selectedItem));
            }
            dataSource.value.forEach((dataItem: any) => {
                const dataItemIdentify = dataItem[identifyField.value];
                const hasSelected = selectionValueMaps.has(dataItemIdentify);
                dataItem.checked = hasSelected;
                if (hasSelected) {
                    selectionMaps.set(dataItemIdentify, dataItem);
                }
            });
        }
        initializeData();

        const shouldShowOptionList = computed(() => displayType.value === 'List');
        const shouldShowOptionTree = computed(() => displayType.value === 'Tree');

        function onSelectionChange(seletedItems: any[]) {
            selections.value = seletedItems.map((item: any) => Object.assign({}, item));
            context.emit('change', selections.value);
        }

        function renderOptionList() {
            return <FListView class="f-utils-fill" data={dataSource.value} multi-select={true} draggable={false}
                header="Search" headerClass="transfer-search-box"
                selection-values={selectionValues.value} onSelectionChange={onSelectionChange}
            > </FListView>;
        }

        function renderOptionTree() {
            return <></>;
        }

        function renderOptionPane() {
            return <div class="f-utils-fill option-pane d-flex flex-column">
                <div class="f-utils-flex-column option-pane-content f-utils-fill">
                    <div class="container columns-box d-flex f-utils-fill">
                        {shouldShowOptionList.value && renderOptionList()}
                        {shouldShowOptionTree.value && renderOptionTree()}
                    </div>
                </div>
            </div>;
        }

        function onRemoveSelectionItem(removedItem: any) {
            const removedItemIdentify = removedItem[identifyField.value];
            if (removedItemIdentify !== null || removedItemIdentify !== undefined) {
                selections.value = selections.value.filter((seletedItem: any) => seletedItem[identifyField.value] !== removedItemIdentify);
                const selectedItemFromDataSource = selectionMaps.get(removedItemIdentify);
                if (selectedItemFromDataSource) {
                    selectedItemFromDataSource.checked = false;
                    selectionMaps.delete(removedItemIdentify);
                }
                context.emit('change', selections.value);
            }
        }

        function onSelectionChanged(seletedItems: any[]) {
            const originalSelectionMap = new Map<string, any>();
            selections.value.reduce((selectionMap: Map<string, any>, item: any) => {
                selectionMap.set(item[identifyField.value], item);
                return selectionMap;
            }, originalSelectionMap);
            selections.value = seletedItems.map((item: any) => originalSelectionMap.get(item[identifyField.value]));
            context.emit('change', selections.value);
        }

        function renderSelectionList() {
            return <FListView style="flex:1" data={selections.value} draggable={true} view="DraggableView" keep-order={true}
                onChange={onSelectionChanged} onRemoveItem={onRemoveSelectionItem}> </FListView>;
        }

        function renderSelectionPane() {
            return <div class="f-utils-fill selection-pane d-flex flex-column">
                <div class="f-utils-flex-column selection-pane-content f-utils-fill">
                    <div class="selection-pane-title">
                        <span class="selection-title">{selectionTitle.value}</span>
                        <span class="selection-count">{selections.value && selections.value.length}</span>
                        <span class="selection-item-title">{selectionItemTitle.value}</span>
                    </div>
                    <div class="container columns-box f-utils-fill d-flex">
                        {renderSelectionList()}
                    </div>
                </div>
            </div>;
        }

        const transferClass = computed(() => {
            const classObject = {
                'transfer': true,
                'row': true,
                'f-utils-fill': fillToParent.value
            } as Record<string, boolean>;
            return classObject;
        });

        return () => {
            return (
                <div class={transferClass.value}>
                    {renderOptionPane()}
                    {renderSelectionPane()}
                </div>
            );
        };
    }
});
